import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.Random;


public class LFSR_3bit_shuffle {

	LinkedList<Integer> lfsr=new LinkedList<Integer>();
	
	//LinkedList<Integer> polinom=new LinkedList<Integer>();
	LinkedList<Polinom> polinomList = new LinkedList<Polinom>();
	
	int dolzina= 6;
	
	public LFSR_3bit_shuffle(){
		
		//generiranje na vrednosti
		/*Random r=new Random();
		Calendar calendar=new GregorianCalendar();
		
		for(int i=0;i<this.dolzina;i++){
			
			int bit=r.nextInt((int)((calendar.getTimeInMillis())%30001+1));
			this.lfsr.add(new Integer(bit%2));		
		}*/
		
		lfsr.add(1);
		lfsr.add(1);
		lfsr.add(0);
		lfsr.add(1);
		lfsr.add(1);
		lfsr.add(0);
	}
	
	public String toString(){
	
		return this.lfsr.toString();
		
	}

	//presmetka za dolzina na lfsr-to
	public void setDolzina(){
		this.dolzina=6;
	}
	
	public LinkedList<Polinom> getPolinom(String fileName) throws IOException{
		
		//LinkedList<Polinom> polinomList=new LinkedList<Polinom>();
		BufferedReader read = new BufferedReader(new FileReader(fileName));
		Polinom tmp;
		String r;
		
		while((r=read.readLine())!=null){
			
			//pomosna promenliva za vnesuvanje na polinomite
			tmp=new Polinom();
			//vnesi ja kvazigrupata
			tmp.setQuasigroup(Integer.parseInt(r));
			tmp.setPolinomi(read.readLine());
			tmp.setPolinomi(read.readLine());
			tmp.setPolinomi(read.readLine());

			this.polinomList.add(tmp);
		}
		
		read.close();
		return polinomList;
	}
	
	public String generateLfsr(String polinom1,String polinom2,String polinom3){

		int bit_output=0;
		int bit_feedback1,bit_feedback2,bit_feedback3;
		
		polinom1=polinom1.replaceAll("\\s", "");	
		String[] pomPolinom1=polinom1.split("\\+");
		String[] monom1;

		polinom2=polinom2.replaceAll("\\s", "");	
		String[] pomPolinom2=polinom2.split("\\+");
		String[] monom2;
		
		polinom3=polinom3.replaceAll("\\s", "");	
		String[] pomPolinom3=polinom3.split("\\+");
		String[] monom3;
				
		/*
		 * ----------------------- Inicijaliziranje na bit_feedback -------------------------- 
		 * */
		int pozicija;
		int pomBit1,pomBit2,pomBit3;
		
		
		//************************* POLINOM1 *********************
		//ako imame 1 na pocetokot na polinomot
		if(pomPolinom1[0].length()<2){
			bit_feedback1=1;
		}
		
		// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja od 0)
		else if(pomPolinom1[0].length()==2){
			pozicija=Integer.parseInt(pomPolinom1[0].substring(1))-1;
			bit_feedback1=this.lfsr.get(pozicija);
		}
		
		//ako imame monom x1*x2*x3 
		else{
			monom1=pomPolinom1[0].split("\\*");
			pozicija=Integer.parseInt(monom1[0].substring(1))-1;
			pomBit1=this.lfsr.get(pozicija);
			
			for (int i = 1; i < monom1.length; i++) {
				pozicija=Integer.parseInt(monom1[i].substring(1))-1;
				pomBit1&=this.lfsr.get(pozicija);
			}
			bit_feedback1=pomBit1;
		}
	//	System.out.println("fidback "+bit_feedback);
		
		for(int i=pomPolinom1.length-1; i>0; i--)
		{
			
			//ako imame 1 na pocetokot na polinomot
			if(pomPolinom1[i].length()<2){
				bit_feedback1^=1;
			}
			// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja od 0)
			else if(pomPolinom1[i].length()==2){
				pozicija=Integer.parseInt(pomPolinom1[i].substring(1))-1;
				bit_feedback1^=this.lfsr.get(pozicija);
			}
			//ako imame monom x1*x2*x3 
			else{
				
				monom1=pomPolinom1[i].split("\\*");
				pozicija=Integer.parseInt(monom1[0].substring(1))-1;
				pomBit1=this.lfsr.get(pozicija);

				for (int j = 1; j < monom1.length; j++) {
					pozicija=Integer.parseInt(monom1[j].substring(1))-1;
					pomBit1&=this.lfsr.get(pozicija);
				}
				bit_feedback1^=pomBit1;
			}

		}

		
		
		//************************* POLINOM2 *********************
				//ako imame 1 na pocetokot na polinomot
				if(pomPolinom2[0].length()<2){
					bit_feedback2=1;
				}
				
				// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja od 0)
				else if(pomPolinom2[0].length()==2){
					pozicija=Integer.parseInt(pomPolinom2[0].substring(1))-1;
					bit_feedback2=this.lfsr.get(pozicija);
				}
				
				//ako imame monom x1*x2*x3 
				else{
					monom2=pomPolinom2[0].split("\\*");
					pozicija=Integer.parseInt(monom2[0].substring(1))-1;
					pomBit2=this.lfsr.get(pozicija);
					
					for (int i = 1; i < monom2.length; i++) {
						pozicija=Integer.parseInt(monom2[i].substring(1))-1;
						pomBit2&=this.lfsr.get(pozicija);
					}
					bit_feedback2=pomBit2;
				}
			//	System.out.println("fidback "+bit_feedback);
				
				for(int i=pomPolinom2.length-1; i>0; i--)
				{
					
					//ako imame 1 na pocetokot na polinomot
					if(pomPolinom2[i].length()<2){
						bit_feedback2^=1;
					}
					// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja od 0)
					else if(pomPolinom2[i].length()==2){
						pozicija=Integer.parseInt(pomPolinom2[i].substring(1))-1;
						bit_feedback2^=this.lfsr.get(pozicija);
					}
					//ako imame monom x1*x2*x3 
					else{
						
						monom2=pomPolinom2[i].split("\\*");
						pozicija=Integer.parseInt(monom2[0].substring(1))-1;
						pomBit2=this.lfsr.get(pozicija);

						for (int j = 1; j < monom2.length; j++) {
							pozicija=Integer.parseInt(monom2[j].substring(1))-1;
							pomBit2&=this.lfsr.get(pozicija);
						}
						bit_feedback2^=pomBit2;
					}

				}


				
				
				
				//************************* POLINOM3 *********************
				//ako imame 1 na pocetokot na polinomot
				if(pomPolinom3[0].length()<2){
					bit_feedback3=1;
				}
				
				// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja od 0)
				else if(pomPolinom3[0].length()==2){
					pozicija=Integer.parseInt(pomPolinom3[0].substring(1))-1;
					bit_feedback3=this.lfsr.get(pozicija);
				}
				
				//ako imame monom x1*x2*x3 
				else{
					monom3=pomPolinom3[0].split("\\*");
					pozicija=Integer.parseInt(monom3[0].substring(1))-1;
					pomBit3=this.lfsr.get(pozicija);
					
					for (int i = 1; i < monom3.length; i++) {
						pozicija=Integer.parseInt(monom3[i].substring(1))-1;
						pomBit3&=this.lfsr.get(pozicija);
					}
					bit_feedback3=pomBit3;
				}
			//	System.out.println("fidback "+bit_feedback);
				
				for(int i=pomPolinom3.length-1; i>0; i--)
				{
					
					//ako imame 1 na pocetokot na polinomot
					if(pomPolinom3[i].length()<2){
						bit_feedback3^=1;
					}
					// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja od 0)
					else if(pomPolinom3[i].length()==2){
						pozicija=Integer.parseInt(pomPolinom3[i].substring(1))-1;
						bit_feedback3^=this.lfsr.get(pozicija);
					}
					//ako imame monom x1*x2*x3 
					else{
						
						monom3=pomPolinom3[i].split("\\*");
						pozicija=Integer.parseInt(monom3[0].substring(1))-1;
						pomBit3=this.lfsr.get(pozicija);

						for (int j = 1; j < monom3.length; j++) {
							pozicija=Integer.parseInt(monom3[j].substring(1))-1;
							pomBit3&=this.lfsr.get(pozicija);
						}
						bit_feedback3^=pomBit3;
					}

				}

		
		
		this.lfsr.addFirst(bit_feedback3);
		this.lfsr.addFirst(bit_feedback2);
		this.lfsr.addFirst(bit_feedback1);
		
		String bitS=String.valueOf(lfsr.getLast());
		this.lfsr.removeLast();

		bitS=String.valueOf(lfsr.getLast())+bitS;
		this.lfsr.removeLast();
		
		bitS=String.valueOf(lfsr.getLast())+bitS;
		this.lfsr.removeLast();
		
//System.out.println("out "+bit_feedback);
		return bitS;
	}
	
    public void toHexa(String readFrom, String writeTo) throws FileNotFoundException, IOException{

        BufferedReader in=new BufferedReader(new FileReader(readFrom));
        BufferedWriter out = new BufferedWriter(new FileWriter(writeTo));

        String input=in.readLine();

        while(input.length()%8!=0){
             input+="0";
        }
        int br=0;

        for(int i=0;i<input.length();){
        	br++;
           int broj= Integer.parseInt(input.substring(i,i+4),2);
           String hexString = Integer.toHexString(broj);
           if(br == 80){
        	   out.write(hexString+"\n");
        	   br=0;
           }
           else{
        	   out.write(hexString);
           }
           i+=4;

       }

         out.close();
     }

	

    public static void main(String[] args) throws InterruptedException, IOException
	{
		

    
    	
    	//za generiranje na polinomi
    	LFSR_3bit_shuffle l=new LFSR_3bit_shuffle();
    	// TUKAAAAAAAAAAAAAAAAAAAA    	
    // 	Polinom p=new Polinom();
  
    	BufferedWriter file1;
    	LFSR_3bit_shuffle lfsr;
		
		LinkedList<Polinom> polinomList= new LinkedList<Polinom>();
		
		
		polinomList=l.getPolinom("polinomi\\polinomi2.txt");
		System.out.println(polinomList.size());
		
		//brojot na kvazigrupata 
		int quasi;
		LinkedList<String> polinomi;// = new LinkedList<>();
	
		String poly1="",poly2="",poly3="";
		
		for(int i=0; i<1/*polinomList.size()*/; i++){
			
			//quasi=polinomList.get(i).getQuasigroup();
			lfsr = new LFSR_3bit_shuffle();
	    	file1 = new BufferedWriter(new FileWriter("datoteki\\q"+(i+1)+".txt"));
			polinomi=polinomList.get(i).getPolinomi();
			
	
			
			String bit="";
			System.out.println("Kvazigrupa "+i);
			//generiranje na golemaaaa datoteka za Diehard /*7980000*/
			for(int j=0; j<2000000; j++){
				
			System.out.println(j);
				poly1=polinomi.get(0);
				poly2=polinomi.get(1);
				poly3=polinomi.get(2);
				
				bit="";
				bit=lfsr.generateLfsr(poly1,poly2,poly3);
				bit=Shuffle.shuffle(bit);
				
					file1.write(bit);
					file1.flush();
				
				
			}

			polinomi.clear();
			//zatvoranje na site datoteki
			file1.close();
		}
		
		
		//tukaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
	
		//konvertiraj ja binarnata datotekata vo hehsa
	//	l.toHexa("q"+quasi+"_1.txt", "hexa.txt");
		
		/*
		//printanje na polinomite izvadeni od datoteka
		System.out.println("Polinomi");
		for(int i=0; i<polinomList.size(); i++){
			System.out.println(polinomList.get(i).toString());
		}
		*/
		
		
		
		
	}
    
    	

}
